The Let's Play Archive

EXAPUNKS

by Carbon dioxide

Part 40: Unknown Network

Part 40 - Unknown Network

=== Trash World Inbox ===

The puzzles are getting really hard to optimize now. Quackles posted a big activity improvement, though.

Quackles posted:

I was able to get roughly the same performance with drastically lower activity. Here's how:
code:
;XA LOCAL

GRAB 300
COPY F X
LINK 800
LINK 801
REPL READY
COPY F X
WIPE
VOID M

MARK READY
MODE         ;global
GRAB 200
MARK CHECK
TEST F = X
FJMP CHECK
COPY 10 T
MARK WRITE
COPY F M
SUBI T 1 T
TJMP WRITE
DROP
MODE
COPY 1 M
This is the first EXA. It's a search utility. As Drive-1 always has the indexes of the rest, it goes into Drive-1, makes a copy of itself, and feeds the copy the first name to look for.

When the copy receives a name, it finds the name in file 200 (the directory file) and sends the 10 values after it out over global M. The original waits for the copy to finish, then it has the second name and does the same kind of search, using code fall-through.

So where does it send the info? Get ready to drink from the firehose.
code:
MAKE
COPY 20 T
MARK READ
COPY M F
SUBI T 1 T
TJMP READ
MODE         ;to local for interleave
REPL INTERLEAVE_READ
SEEK -9999
MARK INTERLEAVE_WRITE
COPY 10 T
MARK ILW2
COPY F M
SEEK 9
COPY F M
SEEK -10
SUBI T 1 T
TJMP ILW2
HALT

MARK INTERLEAVE_READ
COPY 20 T
MAKE
MARK READ2
COPY M F
SUBI T 1 T
TJMP READ2
MODE         ;back to global
             ;ready! now do the rest
LINK 800
REPL BUFFER
LINK 801
KILL
LINK -1 
MODE         ;local for nonbuffer
             ;everything up until this point has been getting a list of src, dest pairs
             ;now: we go off
SEEK -9999
COPY 10 T
MARK MAINLOOP
COPY 1 M
COPY F X
REPL SOURCE
VOID M
COPY F X
REPL DEST
VOID M
SUBI T 1 T
TJMP MAINLOOP
KILL
WIPE
HALT


MARK SOURCE
MODE
SWIZ X 0003 T
ADDI T 800 T
LINK T
SWIZ X 0002 T
ADDI T 200 T
GRAB T
SWIZ X 0010 T
SEEK T
COPY 10 T
MARK WRITETOBUF
COPY F M
SUBI T 1 T
TJMP WRITETOBUF
HALT


MARK DEST
MODE
SWIZ X 0003 T
ADDI T 800 T
LINK T
SWIZ X 0002 T
ADDI T 200 T
GRAB T
SWIZ X 0010 T
SEEK T
COPY 10 T
MARK READFROMBUF
COPY M F
SUBI T 1 T
TJMP READFROMBUF
HALT

MARK BUFFER
MODE
VOID M
MODE
MAKE
COPY 10 T
MARK BUFWRITE
COPY M F
SUBI T 1 T
TJMP BUFWRITE
COPY 10 T
MODE
COPY 1 M     ;write's done
MODE
SEEK -9999
MARK BUFREAD
COPY F M
SUBI T 1 T
TJMP BUFREAD
WIPE
MODE
COPY 1 M     ;read's over
MODE
JUMP BUFFER
All of this is the second EXA. To start, it reads 20 values over global M, then spawns a copy of itself to easily interleave the values. This will end with the values in the order #1, #11, #2, #12, #3, #13, and so on.

Once the interleave is complete, the original stops and the copy goes and kills the leftover search EXA in Drive-1. The copy also replicates itself again, in the Gateway. The replicated EXA can be called the buffer EXA. It sets its M to global.

The copy of the second EXA (not the buffer EXA) now copies itself again, with the new EXA (hereinafter the 'source EXA') directed to go a specific area of the tape. It reads off 10 values from the tape and sends them over Global M, which the buffer EXA picks up, then it halts.

The second-EXA copy repeats the process, creating a 'destination EXA'. This goes to a specific area of the tape, reads the same 10 values from the buffer EXA over global M, writes them to the tape, and halts.

This source-to-dest process repeats ten times. Then, the second-EXA copy kills the buffer EXA, cleans up after itself, and stops. Finished!

Final stats: 1674/126/27.
That interleaving step makes the rest of the process a lot more convenient. Nice solution.

Stepping through your code I did notice that killing the search EXA takes 3 activity (LINK to 801, KILL and LINK back). Could we get rid of that?

Well, all that's needed is for the search EXA to clean itself up.
code:
;XA LOCAL

GRAB 300
COPY F X
LINK 800
LINK 801
DROP

MARK READY

GRAB 200
MARK CHECK
TEST F = X
FJMP CHECK
COPY 10 T
MARK WRITE
COPY F M
SUBI T 1 T
TJMP WRITE
DROP

GRAB 300
SEEK 1
COPY F X
WIPE
JUMP READY
It doesn't use REPLs anymore. Instead, after writing the first value from the file to X, it drops the file on the ground, goes read the index file, and then just picks up file 300 again, to read the second name. Then, it WIPEs the file, before JUMPing into the copy code. That way, when it tries to grab the names file for a third round, it won't find it and instead just die.

Also delete the LINK and KILL lines from the other EXA and we end up with 1671/122/24.

=== Unknown Network ===

Wow. Are you seeing this?
After the information was released, the senator simply admitted to being a clone of the President.
I guess you were just setting it back to the way it was before.
Processing.
Still processing.
That's quite the coincidence.
Not very realistic, if you ask me.
What is going on?




An unanimous vote.

The world was even more fucked up than we thought?

Evidently.
It does fit in with my theory...
In a strange way.
But I should wait for more evidence before I say anything.



[hydroponix] dude politicons cloning themselves, that's nuts
[hydroponix] you should be angry
[x10x10x] they're all the same anyway




Next up, some unknown network?

Remember the friend I was looking for?
I finally found its hideout.




Hideout?

Looks like there are some protections in place.
We need to disable those so I can get in and say hi.




Three votes for "Is this... friendly?" I'm honestly not sure if we're asking whether Ember's friend is friendly, or us hacking the network.

Is this... friendly?

Sure. You know how old friends can be sometimes.
Let's go.



OST: Leave No Trace

I've been in here before. It's that "Department of Applied Semiotics" where Ember wanted me to grab a strange file, back in part 11. I think I can safely assume Ember's friend is also an AI.

The text on the screen in the top left is the only new thing, it translates to "Not connected".

The assignment:

- Terminate all other EXAs and bring any files they were holding back to your host. Only EXAs in the central host will be holding files, and their file IDs will always be between 200 and 299, inclusive.
- Note that some links may become non-traversable as a result of your actions.


It sounds a little weird that we have to "leave no trace" while we have to kill a bunch of their EXAs. Let's figure out what that second point means.



As it turns out, killing one of those EXAs disables the link to the next host (the EXA was killed this cycle and will disappear next cycle), so I'll have to do the killing on the way back.

The number of foreign EXAs per host seems constant, only the amount of files changes between the test cases.

So, let's just hardcode everything with REPs.
code:
@REP 5
LINK 800
@END
@REP 6
KILL
@END
COPY 200 X
MARK GRABLP
REPL GRAB
ADDI X 1 X
TEST X = 300
FJMP GRABLP
@REP 5
LINK -1
KILL
KILL
@END

MARK GRAB
GRAB X
@REP 5
LINK -1
@END
First, it LINKs to 800 five times to get to the center, then it KILLs all 6 EXAs there, and then it generates REPLs to bring the files home. If a file doesn't exist, the REPL just dies. Finally, the main EXA traverses the network in reverse and KILLs the foreign EXAs.

Except it doesn't work. Turns out that if you KILL a foreign EXA in any host except for the center one, the other EXA in the host will KILL your EXA in return. Oops, that wasn't in the description.

Making a REPL which then does the KILL command doesn't work either because KILL always prioritizes your own EXAs. And I can't even have another EXA wait in the center host to go KILL the second foreign EXA, because killing the first already shuts down that link. The other one needs to be closer to our home host. Hmmm, this is trickier than I thought.

code:
;XA LOCAL
@REP 5
REPL WAIT
LINK 800
@END
@REP 6
KILL
@END
COPY 200 X
MARK GRABLP
REPL GRAB
ADDI X 1 X
TEST X = 300
FJMP GRABLP

@REP 5
LINK -1
COPY 0 M
@END


MARK GRAB
GRAB X
@REP 5
LINK -1
@END
HALT

MARK WAIT
VOID M
REPL KILLER
KILL

MARK KILLER
LINK 800
KILL
Now, on the way there, the EXA leaves waiting EXAs everywhere, including in the home host. It still kills the center EXAs as before, and sends REPLs back with the files. But then, as it walks back home, it activates each waiting EXA in turn.

The waiting EXA does two things: it sends a KILLER up towards the center and then it KILLs an EXA in its own host. That way, in each host first the waiting EXA will KILL a foreign EXA, then another EXA will LINK in from the previous host and kill the second EXA. One cycle later, the first foreign EXA in the previous host will be killed, disabling the link, so it all happens just in time.



437/47/63, with top percentiles of 74, 21 and 49. Looking at the graphs, I seem to have hit upon a common solution.

By the way, the files are uncomprehensible 'nonsense' again. Just random-looking numbers. Similar to the last time we were in this network.


Let's take a look at optimizations. My EXAs are jumping back and forth quite a lot, looks like I should be able to improve the activity.

Know how I said KILLing one of the EXAs outside of the center host makes the other KILL yours? That's true, but it only happens a cycle later, so your EXA can do one more instruction before being killed. Mutual assured destruction is possibly by making that another KILL.

code:
;XA GLOBAL

LINK 800
@REP 4
REPL WAIT
LINK 800
@END
@REP 6
KILL
@END
COPY 200 X
MARK GRABLP
REPL GRAB
ADDI X 1 X
TEST X = 300
FJMP GRABLP

@REP 4
COPY 0 M
@END


MARK GRAB
GRAB X
@REP 5
LINK -1
@END
HALT

MARK WAIT
VOID M
KILL
KILL
Similar as before, but each waiting EXA just KILLs twice. Apparently the last file-carrying EXA is always faster so just triggering them over global M works perfectly fine. 427/37/49.

For a low cycle solution, there's no reason why I can't have a bunch of EXAs looking for the files in parallel.
code:
;XA GLOBAL
LINK 800
@REP 4
REPL WAIT
LINK 800
@END
@REP 6
KILL
@END
@REP 7
COPY @{200,13} X
REPL GRABLP
@END
COPY 288 X
MARK GRABLP
REPL GRAB
ADDI X 1 X
TEST X = 300
FJMP GRABLP

@REP 4
COPY 0 M
@END
@REP 9
KILL
@END

MARK GRAB
GRAB X
@REP 5
LINK -1
@END
HALT

MARK WAIT
VOID M
KILL
KILL
The COPY @{200,13} X line unwraps to COPY 200 X, COPY 213 X, and so on. This way, 7 REPLs and the original each start looking from a different offset. The original, which starts from the highest offset is the only one to reach 300 and KILLs all the others when it's done.
I chose to use 8 EXAs because that's the maximum I could get working. Any more, and their loops will be so short that they start exiting their loop early, triggering the M messages or the KILLs and causing all sorts of trouble. Even with 8, I needed a couple additional KILLs to deal with some stray GRAB EXAs.

111/60/58.


To reduce the size a bit, I can take the 37 cycle solution and just roll up some of the loops. For instance, this solution is 34 lines.
code:
LINK 800

COPY 4 T
MARK LP1
REPL WAIT
LINK 800
SUBI T 1 T
TJMP LP1

COPY 6 T
MARK LP2
KILL
SUBI T 1 T
TJMP LP2
COPY 200 X
MARK GRABLP
REPL GRAB
ADDI X 1 X
TEST X = 300
FJMP GRABLP

@REP 4
COPY 0 M
@END


MARK GRAB
GRAB X
@REP 5
LINK -1
@END
HALT

MARK WAIT
VOID M
KILL
KILL
And now that activity doesn't matter anymore, the main EXA can directly go KILL the foreign ones, so I don't need M. Also, it feels like a waste to have two size-5 LINK loops, so let's combine them.
code:
COPY 800 X

COPY 5 T
MARK LP1
LINK X
SUBI T 1 T
TJMP LP1

COPY 6 T
MARK LP2
KILL
SUBI T 1 T
TJMP LP2


COPY 200 X
MARK GRABLP
REPL GRAB
ADDI X 1 X
TEST X = 302
FJMP GRABLP

MARK KILL
LINK -1
REPL KILL
KILL
KILL

MARK GRAB
GRAB X
COPY -1 X
JUMP LP1
Size 26. The order in the REPL KILL structure makes sure that an EXA makes it back before the link gets closed.
Jumping directly into LP1 from the grabber works, because T is 0 at that time, the first SUBI will drop it to -1, and any negative T is true. It'll go into an infinite loop, and dies once it reaches home and there's no -1 to LINK to. Note that I had to increase the endpoint of the file seeker to 302 to prevent it from killing the much slower grabbers on the way.

Speaking of, if you're willing to accept a much slower solution, I can bring the size down to 25. Just use T for the GRABLP and let it run down to 0.
code:
COPY 800 X

COPY 5 T
MARK LP1
LINK X
SUBI T 1 T
TJMP LP1

COPY 6 T
MARK LP2
KILL
SUBI T 1 T
TJMP LP2


COPY 300 T
MARK GRABLP
REPL GRAB
SUBI T 1 T
TJMP GRABLP

MARK KILL
LINK -1
REPL KILL
KILL
KILL


MARK GRAB
GRAB T
COPY -1 X
JUMP LP1
T will be 200-something when it reaches LP1 to return, so it'll always run often enough. Final result: 951/25/56.

I wasn't always so capable, but I've grown.
Nothing hides from me for long.




The first vote.






Yet another cutscene with Ember.

Well, always nice to reconnect with an old friend.



Since this is related to the previous conversation, I'll actually end the update here and make this the second vote.